import mongoose, { Document, Schema, Model } from 'mongoose';

/**
 * 角色接口定义
 * 定义角色的基本属性
 */
export interface IRole {
  /** 角色名称 */
  name: string;
  /** 角色编码，唯一标识 */
  code: string;
  /** 角色描述 */
  description?: string;
  /** 角色级别 */
  level: number;
  /** 所属系统ID */
  systemId?: mongoose.Types.ObjectId;
  /** 状态：1-正常，0-禁用 */
  status: number;
  /** 创建时间 */
  createdAt: Date;
  /** 更新时间 */
  updatedAt: Date;
}

/**
 * 角色文档接口
 * 继承IRole接口和mongoose的Document接口
 */
export interface IRoleDocument extends IRole, Document {
  /**
   * 转换为JSON格式，用于API响应
   * @returns 格式化的角色对象
   */
  toJSON(): any;

  /**
   * 检查角色是否为系统角色
   * @returns 是否为系统角色
   */
  isSystemRole(): boolean;

  /**
   * 检查角色是否可以被删除
   * @returns 是否可以删除
   */
  canBeDeleted(): Promise<boolean>;

  /**
   * 获取角色的权限数量
   * @returns 权限数量
   */
  getPermissionCount(): Promise<number>;

  /**
   * 获取角色的用户数量
   * @returns 用户数量
   */
  getUserCount(): Promise<number>;
}

/**
 * 角色模型接口
 * 定义角色模型的静态方法
 */
export interface IRoleModel extends Model<IRoleDocument> {
  /**
   * 根据角色编码查找角色
   * @param code 角色编码
   * @returns 角色文档或null
   */
  findByCode(code: string): Promise<IRoleDocument | null>;

  /**
   * 根据角色名称查找角色
   * @param name 角色名称
   * @returns 角色文档或null
   */
  findByName(name: string): Promise<IRoleDocument | null>;

  /**
   * 根据系统ID查找角色
   * @param systemId 系统ID
   * @returns 角色文档数组
   */
  findBySystemId(systemId: mongoose.Types.ObjectId): Promise<IRoleDocument[]>;

  /**
   * 根据角色级别查找角色
   * @param level 角色级别
   * @returns 角色文档数组
   */
  findByLevel(level: number): Promise<IRoleDocument[]>;

  /**
   * 根据状态查找角色
   * @param status 状态值
   * @returns 角色文档数组
   */
  findByStatus(status: number): Promise<IRoleDocument[]>;

  /**
   * 获取系统内置角色
   * @returns 系统角色数组
   */
  getSystemRoles(): Promise<IRoleDocument[]>;

  /**
   * 检查角色编码是否存在
   * @param code 角色编码
   * @param excludeId 排除的角色ID（用于更新时检查）
   * @returns 是否存在
   */
  isCodeExists(code: string, excludeId?: mongoose.Types.ObjectId): Promise<boolean>;

  /**
   * 检查角色名称是否存在
   * @param name 角色名称
   * @param excludeId 排除的角色ID（用于更新时检查）
   * @returns 是否存在
   */
  isNameExists(name: string, excludeId?: mongoose.Types.ObjectId): Promise<boolean>;
}

/**
 * 角色数据模型Schema定义
 * 定义角色在MongoDB中的数据结构和验证规则
 */
const RoleSchema = new Schema<IRoleDocument>({
  // 角色名称：必填，最大长度50，去除首尾空格
  name: {
    type: String,
    required: [true, '角色名称不能为空'],
    trim: true,
    maxlength: [50, '角色名称不能超过50个字符'],
    index: true
  },

  // 角色编码：必填，唯一，最大长度30，只能包含字母数字下划线
  code: {
    type: String,
    required: [true, '角色编码不能为空'],
    unique: true,
    trim: true,
    maxlength: [30, '角色编码不能超过30个字符'],
    match: [/^[a-zA-Z0-9_]+$/, '角色编码只能包含字母、数字和下划线'],
    index: true
  },

  // 角色描述：可选，最大长度200
  description: {
    type: String,
    trim: true,
    maxlength: [200, '角色描述不能超过200个字符']
  },

  // 角色级别：必填，数字类型，最小值1
  level: {
    type: Number,
    required: [true, '角色级别不能为空'],
    min: [1, '角色级别不能小于1'],
    index: true
  },

  // 所属系统ID：可选，引用系统表
  systemId: {
    type: Schema.Types.ObjectId,
    ref: 'System',
    index: true
  },

  // 状态：必填，枚举值0或1，默认为1
  status: {
    type: Number,
    required: true,
    enum: [0, 1],
    default: 1,
    index: true
  }
}, {
  // 自动添加创建时间和更新时间
  timestamps: true,
  // 设置集合名称
  collection: 'roles',
  // 禁用版本键
  versionKey: false
});

// 创建复合索引
// 角色编码唯一索引
RoleSchema.index({ code: 1 }, { unique: true });

// 系统ID和状态复合索引，用于查询系统下的活跃角色
RoleSchema.index({ systemId: 1, status: 1 });

// 角色级别和状态复合索引，用于按级别查询活跃角色
RoleSchema.index({ level: 1, status: 1 });

// 状态和创建时间复合索引，用于按状态和时间排序
RoleSchema.index({ status: 1, createdAt: -1 });

// 保存前中间件：数据验证和处理
RoleSchema.pre('save', function(next) {
  // 如果是新文档或者code字段被修改，转换为小写
  if (this.isNew || this.isModified('code')) {
    this.code = this.code.toLowerCase();
  }
  
  // 如果是新文档，设置默认值
  if (this.isNew) {
    // 只有当status未定义时才设置默认值，避免覆盖显式设置的0值
    if (this.status === undefined) {
      this.status = 1;
    }
  }
  
  next();
});

// 更新前中间件：处理更新操作
RoleSchema.pre(['updateOne', 'findOneAndUpdate'], function(next) {
  const update = this.getUpdate() as any;
  
  // 如果更新了code字段，转换为小写
  if (update.code) {
    update.code = update.code.toLowerCase();
  }
  
  // 自动更新updatedAt字段
  update.updatedAt = new Date();
  
  next();
});

// 实例方法：转换为JSON格式
RoleSchema.methods.toJSON = function() {
  const roleObject = this.toObject();
  
  // 移除敏感字段
  delete roleObject.__v;
  
  // 格式化时间字段
  if (roleObject.createdAt) {
    roleObject.createdAt = roleObject.createdAt.toISOString();
  }
  if (roleObject.updatedAt) {
    roleObject.updatedAt = roleObject.updatedAt.toISOString();
  }
  
  return roleObject;
};

// 实例方法：检查是否为系统角色
RoleSchema.methods.isSystemRole = function(): boolean {
  // 系统角色通常级别为1或者编码以system_开头
  return this.level === 1 || this.code.startsWith('system_');
};

// 实例方法：判断角色是否可以删除
RoleSchema.methods.canBeDeleted = async function(): Promise<boolean> {
  // 系统内置角色不能删除
  if (this.isSystemRole()) {
    return false;
  }
  
  // 由于UserRole模型可能未定义，暂时返回true
  return true;
};

// 实例方法：获取角色的权限数量
RoleSchema.methods.getPermissionCount = async function(): Promise<number> {
  // 由于RolePermission模型可能未定义，返回0
  return 0;
};

// 实例方法：获取角色的用户数量
RoleSchema.methods.getUserCount = async function(): Promise<number> {
  // 由于UserRole模型可能未定义，返回0
  return 0;
};

// 静态方法：根据角色编码查找角色
RoleSchema.statics.findByCode = function(code: string): Promise<IRoleDocument | null> {
  return this.findOne({ code: code.toLowerCase() });
};

// 静态方法：根据角色名称查找角色
RoleSchema.statics.findByName = function(name: string): Promise<IRoleDocument | null> {
  return this.findOne({ name });
};

// 静态方法：根据系统ID查找角色
RoleSchema.statics.findBySystemId = function(systemId: mongoose.Types.ObjectId): Promise<IRoleDocument[]> {
  return this.find({ systemId, status: 1 }).sort({ level: 1, createdAt: -1 });
};

// 静态方法：根据角色级别查找角色
RoleSchema.statics.findByLevel = function(level: number): Promise<IRoleDocument[]> {
  return this.find({ level, status: 1 }).sort({ createdAt: -1 });
};

// 静态方法：根据状态查找角色
RoleSchema.statics.findByStatus = function(status: number): Promise<IRoleDocument[]> {
  return this.find({ status }).sort({ level: 1, createdAt: -1 });
};

// 静态方法：获取系统内置角色
RoleSchema.statics.getSystemRoles = function(): Promise<IRoleDocument[]> {
  return this.find({
    $or: [
      { level: 1 },
      { code: { $regex: '^system_' } }
    ],
    status: 1
  }).sort({ level: 1, createdAt: -1 });
};

// 静态方法：检查角色编码是否存在
RoleSchema.statics.isCodeExists = async function(
  code: string, 
  excludeId?: mongoose.Types.ObjectId
): Promise<boolean> {
  const query: any = { code: code.toLowerCase() };
  if (excludeId) {
    query._id = { $ne: excludeId };
  }
  
  const count = await this.countDocuments(query);
  return count > 0;
};

// 静态方法：检查角色名称是否存在
RoleSchema.statics.isNameExists = async function(
  name: string, 
  excludeId?: mongoose.Types.ObjectId
): Promise<boolean> {
  const query: any = { name };
  if (excludeId) {
    query._id = { $ne: excludeId };
  }
  
  const count = await this.countDocuments(query);
  return count > 0;
};

// 导出角色模型
export const Role = mongoose.model<IRoleDocument, IRoleModel>('Role', RoleSchema);

// 默认导出
export default Role;